#pragma once
#ifndef SCNET_SOCKETWRAPPER_HPP
#define SCNET_SOCKETWRAPPER_HPP

#include <sys/socket.h>      // 提供套接字相关的函数，如 socket()、bind() 等
#include <netinet/in.h>      // 提供互联网协议族的地址结构
#include <unistd.h>          // 提供操作系统接口，如 close()
#include <stdexcept>         // 用于抛出异常
#include <memory>
#include <mutex>

// 封装常见的套接字操作  实现数据间通信
namespace scNet {
	// Socket 包装器
	// 操作系统提供的低级网络操作，提供了对套接字的创建、绑定、监听、连接、接收和发送的封装
	class SocketWrapper {
	private:
		int sockfd_ = -1;	// 套接字的文件描述符
		mutable std::mutex mutex_;

	public:
		// 构造 创建套接字
		/**
    	 * @brief 构造函数，创建套接字
    	 * @param domain 套接字域，通常使用 AF_INET（IPv4）或 AF_INET6（IPv6）
    	 * @param type 套接字类型，通常使用 SOCK_STREAM（TCP）或 SOCK_DGRAM（UDP）
    	 * @param protocol 协议类型，默认为0，表示使用默认协议
    	 * 
    	 * 创建一个套接字，失败抛运行时异常。
    	 */
		explicit SocketWrapper(int domain, int type, int protocol = 0);
		// 新增构造函数，接受现有的客户端文件描述符
    	explicit SocketWrapper(int sockfd);  // 新增的构造函数

		/**
    	 * @brief 析构函数，关闭套接字
    	 * 如果套接字有效，关闭套接字，释放资源。
    	 */
		~SocketWrapper();

		// 禁止拷贝
		SocketWrapper(const SocketWrapper&) = delete;
		SocketWrapper& operator=(const SocketWrapper&) = delete;

		// 允许移动
    	SocketWrapper(SocketWrapper&& other) noexcept;
    	SocketWrapper& operator=(SocketWrapper&& other) noexcept;

		/**
		 * @brief 绑定套接字到地址
		 * @param addr 地址结构 指定要绑定的地址
		 * @param addrlen 地址结构长度
		 * 套接字绑定到指定地址 失败抛running time 异常
		 */
		void bind(const struct sockaddr* addr, socklen_t addrlen);

		/**
		 * @brief 监听套接字
		 * @param backloglen 等待队列的最大长度
		 */
		void listen(int backloglen);

		/**
		 * @brief 接受连接
		 * @param addr 客户端地址结构
    	 * @param addrlen 地址结构的长度
    	 * @return 客户端连接的套接字文件描述符
		 * 接受客户端的连接请求，返回与客户端连接的套接字文件描述符。接受连接失败，抛出异常
		 */
		int accept(struct sockaddr* addr, socklen_t* addrlen);

		/**
		 * @brief 连接到指定服务器
		 * @param addr 服务器的地址结构
		 * @param addrlen 地址结构的长度
		 * 客户端连接到指定的服务器。失败抛运行时异常
		 */
		void connect(const struct sockaddr* addr, socklen_t addrlen);

		/**
    	 * @brief 发送数据
    	 * @param buf 要发送的数据缓冲区
    	 * @param len 数据长度
    	 * @param flags 发送标志，默认为0
    	 * @return 发送的字节数
    	 * 
    	 * 通过套接字发送数据。发送失败返回负值。
    	 */
    	ssize_t send(const void* buf, size_t len, int flags = 0);
	
    	/**
    	 * @brief 接收数据
    	 * @param buf 数据接收缓冲区
    	 * @param len 缓冲区大小
    	 * @param flags 接收标志，默认为0
    	 * @return 接收到的字节数
    	 * 
    	 * 通过套接字接收数据接收失败返回负值。
    	 */
    	ssize_t recv(void* buf, size_t len, int flags = 0);
	
    	/**
    	 * @brief 获取套接字文件描述符
    	 * @return 套接字文件描述符
    	 * 
    	 * 返回当前套接字的文件描述符。
    	 */
    	int getFd() const;

		// 设置非阻塞
		void setNonBlocking(bool nonBlocking);
		// 设置停止标准
		void setTimeout(int timeoutsMs);
	};
	
}

#endif // SCNET_SOCKETWRAPPER_HPP